namespace Example {

// Example of Flex + Lemon.

int main(string[] args)
{	stdout.puts("Hi! I can solve mathematical (infix) expressions. Please, print an expression and i will tell you it's result. Terminate input with either Ctrl+D or a semicolon. I will complain on invalid token (something not a number and a sign), and on syntax errors (e.g. two consequent numbers or signs). I will tell you on which line error occured. Example of input: (2+2) * 10;.\n");
	var s = new InfixSolver();
	s.add_stream(stdin); // another alternative: add_string()
	s.end();
	stdout.printf("Result = %f\n", s.result);
	return 0;
}

public struct Location
{	public int line;
	public int line_char;
}

// There are 3 classes needed to Lemon: token_type, extra_argument and start_symbol.
// These classes must be defined in the same namespace.
// For each namespace different Lemon parser is produced.
// The token_type class must be inherited from GLib.Object.
[Lemon(token_type = true)]
public class Token : GLib.Object
{	public Location location;
	public string? value = null;

	public Token(Location location, string? value=null)
	{	this.location = location;
		this.value = value;
	}
}

// The extra_argument class inherits from autogenerated InfixSolverParser.
// Whatever name you give to this class, the generated one will be with "Parser" suffix.
// We use "InfixSolver : InfixSolverParser", but it could be "Foobar : FoobarParser".
[	Lemon
	(	extra_argument = true,
		left = "PLUS MINUS",
		left = "MUL DIV"
	)
]
public class InfixSolver : InfixSolverParser
{	protected int line = 1;
	public double result = 0;

	[Flex(pattern = "[\\r\\n]")]
	public void newline(string value, int value_len)
	{	line++;
		// each time a new token is added, InfixSolverParser adds it's length to n_chars_read
		n_chars_read = 0;
		token_code = TokenCode.NO_ADD_TOKEN;
	}

	protected Location location
	{	get
		{	return Location() {line=line, line_char=n_chars_read+1};
		}
	}

	// The name of function ("number" in this case) turns to be the name of the terminal token ("NUMBER").
	// That means, by default token_code = TokenCode.NUMBER will be added.
	// Though, the function may change token_code to something else.
	// All the known token codes include:
	// 1) Names of functions marked with [Flex()] attribute.
	// 2) Words occured in Lemon patterns (see below) consisting from capital letters only.
	// 3) Words defined by [Flex(token = "NAME1 NAME2 NAME3")].
	// 4) Words defined by [Lemon(left = "NAME1 NAME2 NAME3")].
	// 5) Words defined by [Lemon(right = "NAME1 NAME2 NAME3")].
	// 6) Words defined by [Lemon(nonassoc = "NAME1 NAME2 NAME3")].
	// If the function doesn't set token_code = TokenCode.NO_ADD_TOKEN, then add_token(token_code, token)
	// will be called right after it, to supply the new token to Lemon.
	[Flex(pattern = "[0-9]+ | [0-9]*\\.[0-9]+")]
	public void number(string value, int value_len) {token = new Token(location, value);}

	[Flex(pattern = "\\+")]
	public void plus(string value, int value_len) {}

	[Flex(pattern = "\\-")]
	public void minus(string value, int value_len) {}

	[Flex(pattern = "\\*")]
	public void mul(string value, int value_len) {}

	[Flex(pattern = "\\/")]
	public void div(string value, int value_len) {}

	[Flex(pattern = "\\(")]
	public void paren_open(string value, int value_len) {}

	[Flex(pattern = "\\)")]
	public void paren_close(string value, int value_len) {}

	// There are 2 special codes in TokenCode: END_OF_INPUT and NO_ADD_TOKEN.
	[Flex(pattern = ";")]
	public void semicolon(string value, int value_len)
	{	token_code = TokenCode.END_OF_INPUT;
	}

	// None of patterns declared above were matched.
	public override void on_default_token(string value, int value_len)
	{	assert(value_len == 1); // Flex's behavior is to pass single character
		if (value[0]==' ' || value[0]=='\t')
		{	token_code = TokenCode.NO_ADD_TOKEN;
		}
		else
		{	set_error(location, @"Invalid input: $value");
		}
	}

	public override void on_syntax_error()
	{	set_error(location, "Syntax error");
	}

	protected void set_error(Location location, string message)
	{	stderr.printf("%s at line %d char %d\n", message, location.line, location.line_char);
		is_match = false;
	}
}

public class Symbol : GLib.Object
{	public Location location;
}

// The start_symbol class must be inherited from GLib.Object.
// It represents the whole syntactic unit.
[Lemon(start_symbol = true)]
public class TranslationUnit : Symbol
{	// The pattern says that TranslationUnit is just Expr.
	// Non terminal symbols in patterns must appear in CamelCase. Terminals must be CAPITALIZED.
	// The first argument to function is what is marked with "extra_argument = true" in current namespace:
	// InfixSolver in our case. The only instance of it was constructed in main().
	[Lemon(pattern = "Expr(a)")]
	public TranslationUnit(InfixSolver solver, Expr a)
	{	solver.result = a.value;
	}
}

// Class representing nonterminal symbol "Expr"
public class Expr : AtomicExpr
{	// Expr can be AtomicExpr
	[Lemon(pattern = "AtomicExpr(a)")]
	public Expr._1(InfixSolver solver, AtomicExpr a)
	{	location = a.location;
		value = a.value;
	}

	// Expr can also be sequence of symbols "Expr PLUS Expr"
	[Lemon(pattern = "Expr(a) PLUS Expr(b)")]
	public Expr._2(InfixSolver solver, Expr a, Expr b)
	{	location = a.location;
		value = a.value + b.value;
	}

	[Lemon(pattern = "Expr(a) MINUS Expr(b)")]
	public Expr._3(InfixSolver solver, Expr a, Expr b)
	{	location = a.location;
		value = a.value - b.value;
	}

	[Lemon(pattern = "Expr(a) MUL Expr(b)")]
	public Expr._4(InfixSolver solver, Expr a, Expr b)
	{	location = a.location;
		value = a.value * b.value;
	}

	[Lemon(pattern = "Expr(a) DIV Expr(b)")]
	public Expr._5(InfixSolver solver, Expr a, Expr b)
	{	location = a.location;
		value = a.value / b.value;
	}
}

// Class representing nonterminal symbol "AtomicExpr"
public class AtomicExpr : Symbol
{	public double value;

	// The type of terminal symbol is Token, since it was marked as "token_type = true".
	[Lemon(pattern = "NUMBER(a)")]
	public AtomicExpr._1(InfixSolver solver, Token a)
	{	location = a.location;
		value = double.parse(a.value);
	}

	[Lemon(pattern = "PLUS AtomicExpr(a)")]
	public AtomicExpr._2(InfixSolver solver, AtomicExpr a)
	{	location = a.location;
		value = a.value;
	}

	[Lemon(pattern = "MINUS AtomicExpr(a)")]
	public AtomicExpr._3(InfixSolver solver, AtomicExpr a)
	{	location = a.location;
		value = -a.value;
	}

	// This one is special. Instead of writing constructor for Lemon action,
	// we use a static method that returns an instance of this class (AtomicExpr).
	// This approach is good when there is already instance available, so no need to construct.
	[Lemon(pattern = "PAREN_OPEN Expr(a) PAREN_CLOSE")]
	public static AtomicExpr _4(InfixSolver solver, Expr a)
	{	return a as AtomicExpr;
	}
}

} // end namespace
